#!/bin/bash
###############################################
# File Name : mem_scam.sh
# Version : V1.0
# Auther : frankjpliu@tencent.com kkingzhang@tencent.com
# Organization : NULL
###############################################
GREEN='\033[1;32m'
RED='\033[1;31m'
BLUE='\033[1;34m'
NC='\033[0m'

drop_caches=0
mem_cost_topn=3

usage="\
Usage:
	oc-ops mem checkcost [-n topn] [-d] [-h]
	COMMAND-LINE Options:
	-n	topn表示前topn的内存耗用项，默认显示 top 3 的内存耗用项
	-d	先drop cache (echo 3 > /proc/sys/vm/drop_caches)，再进行内存消耗检测
	-h	显示oc-ops mem checkcost的用法，并退出
"

function get_all_process_oorderbymem_res()
{
	top -b -o "%MEM" -n 1 | head -n 60
}

function get_slabtop()
{
	slabtop -o 1 -s l | head -n 60
}

function tmpfs_analysis()
{
	if [ $# -gt 0 ] && [ $0 -gt 0 ];then
		mem_total=$0
		for item in `df -k | grep tmpfs`
		do
			tmpfs_usage=`echo $item | awk '{print $2}'`
			percent=`echo | awk '{tmp=(('$tmpfs_usage'/'$mem_total')*100);if (tmp >= 5.0){print 1} else {print 0}}'`
			if [ $percent -eq 1 ];then
				# >= 5%
				echo $item
			fi
		done
	else
		echo "confirm total mem!"
	fi
}

function vmallocinfo_analysis()
{
	awk '{s[$3] += $2}END{ for(i in s){ print i, ":" ,s[i] } }' /proc/vmallocinfo
}

function get_process_hugetlbfs()
{
	for pid in `grep "KernelPageSize:     2048 kB" /proc/*/smaps 2>/dev/null | awk '{print $1}' | cut -d "/" -f3 | sort | uniq`
	do
		tmp=`echo $pid | grep -e [0-9]`
		if [ "X$tmp" != "X" ];then
			total=`grep -B 11 'KernelPageSize:     2048 kB' /proc/$pid/smaps 2>/dev/null | grep '^Size:' | awk 'BEGIN{sum=0}{sum+=$2}END{print sum/1024}'`
			pname=`head -n 1 /proc/$pid/stat 2>/dev/null | cut -d " " -f 2 | tr -d "()"`
			echo "" | awk '{printf ("%20s ","'$pname'");printf ("%20s ","'$pid'");printf ("%20s\r\n", "'$total'")}'
		fi
	done
}

function mem_usage_detail()
{
	local mem_total=0

	if (( $1 == 1 )); then
		echo 3 > /proc/sys/vm/drop_caches
	fi

	topn_ajusted=$(( $mem_cost_topn + 1 ))

	for item in `awk '{if ($1=="MemTotal:"){mem_total=$2;sub(/:/,"",$1);print mem_total":"$1};if ($1=="AnonPages:"){sub(/:/,"",$1);print $2":"$1};if ($1=="Shmem:"){sub(/:/,"",$1);print $2":"$1};if ($1=="Slab:"){sub(/:/,"",$1);print $2":"$1};if ($1=="VmallocUsed:"){sub(/:/,"",$1);print $2":"$1};if ($1=="HugePages_Total:"){sub(/:/,"",$1);print $2":"$1};if ($1=="Buffers:"){sub(/:/,"",$1);print $2":"$1};if ($1=="Cached:"){sub(/:/,"",$1);print $2":"$1}}' /proc/meminfo | sort -nr | head -n $topn_ajusted`
	do
		domain=`echo $item | awk -F ":" '{print $NF}'`
		echo "$domain"
		case $domain in
			"Cached")
				value=`echo $item | awk -F ":" '{print $1}'`
				percent=`echo $value $mem_total | awk '{printf ("%2.2f%",int($1)/int($2)*100)}'`
				echo -e "Cached / mem_total: ${RED} $percent ${NC}"
				;;
			"Buffers")
				value=`echo $item | awk -F ":" '{print $1}'`
				percent=`echo $value $mem_total | awk '{printf ("%2.2f%",int($1)/int($2)*100)}'`
				echo -e "Buffers / mem_total: ${RED} $percent ${NC}"
				;;
			"AnonPages")
				get_all_process_oorderbymem_res
				;;
			"Shmem")
				tmpfs_analysis 
				;;
			"Slab")
				get_slabtop
				;;
			"VmallocUsed")
				vmallocinfo_analysis $mem_total
				;;
			"HugePages_Total")
				get_process_hugetlbfs
				;;
			"MemTotal")
				mem_total=`echo $item | awk -F ":" '{print $1}'`
				echo "mem_total: $mem_total"
				;;
			*)
				;;
		esac
		echo ""
		echo "-----------------------------------------------------------"
	done
}

while getopts 'n:dh' OPT; do
        case $OPT in
                n)      mem_cost_topn="$OPTARG"
                        ;;
                d)      drop_caches=1
                        ;;
                h)      echo "$usage"
                        exit $?
                        ;;
                ?)      echo "Invalid option: $OPT" >&2
                        echo "$usage"
                        exit 1
                        ;;
        esac
done

mem_usage_detail $drop_caches
